package session

import (
	"fmt"
	"git.hortorgames.com/orange/tang/log"
	"git.hortorgames.com/orange/tang/redis"
	"time"
)

func Init(sess *redis.Session, playerId int64, token string, reqSeq int, data []byte) (err error) {
	lk := redis.NewLocker(sess, fmt.Sprintf("htg.session:{%d}:lock", playerId))
	err = lk.Lock()
	if err != nil {
		return
	}
	defer lk.UnLock()
	_, err = sess.Eval(redis.ScriptFromAssetMust(init_lua), []string{
		fmt.Sprintf("htg.session:{%d}:info", playerId),
		fmt.Sprintf("htg.session:{%d}:req", playerId),
		fmt.Sprintf("htg.session:{%d}:resp", playerId),
	}, token, reqSeq, data, 3600*24)
	return
}

func CheckToken(sess *redis.Session, playerId int64, token string) (valid bool, expireAt int64, err error) {
	var rs interface{}
	rs, err = sess.EvalOneKey(redis.ScriptFromAssetMust(check_token_lua),
		fmt.Sprintf("htg.session:{%d}:info", playerId),
		token,
		time.Now().Unix())
	if err != nil {
		log.Error("CheckToken error", "err", err.Error())
		return
	}
	rsm, ok := rs.([]interface{})
	if !ok {
		log.Error("CheckToken result is not string")
		return
	}
	valid = rsm[0].(int64) == 1
	expireAt = rsm[1].(int64)
	return
}

func AddReq(sess *redis.Session, playerId int64, reqSeq int, data []byte) (resp []byte, err error) {
	if playerId == 0 {
		return nil, nil
	}
	var rs interface{}
	rootKey := fmt.Sprintf("htg.session:{%d}:info", playerId)
	reqKey := fmt.Sprintf("htg.session:{%d}:req", playerId)
	respKey := fmt.Sprintf("htg.session:{%d}:resp", playerId)
	rs, err = sess.Eval(redis.ScriptFromAssetMust(add_req_lua), []string{
		rootKey,
		reqKey,
		respKey,
	}, reqSeq, data, 3600*24)
	if err != nil {
		return nil, err
	}
	rss, ok := rs.(string)
	if !ok {
		return nil, fmt.Errorf("result is not string")
	}
	switch rss {
	case "ok":
		return nil, nil
	case "waiting":
		timeout := time.Now().Add(time.Second * 10)
		time.Sleep(time.Millisecond * 10)
		for {
			exists, rs, err := sess.HGet(respKey, fmt.Sprint(reqSeq))
			if err != nil {
				return nil, err
			}
			if exists {
				return []byte(rs), nil
			}
			if time.Now().After(timeout) {
				return nil, fmt.Errorf("timeout")
			}
			time.Sleep(time.Millisecond * 100)
		}
	default:
		return []byte(rss), nil
	}
	return
}

func AddResp(sess *redis.Session, playerId int64, reqSeq int, data []byte) (err error) {
	if playerId == 0 {
		return nil
	}
	rootKey := fmt.Sprintf("htg.session:{%d}:info", playerId)
	reqKey := fmt.Sprintf("htg.session:{%d}:req", playerId)
	respKey := fmt.Sprintf("htg.session:{%d}:resp", playerId)
	_, err = sess.Eval(redis.ScriptFromAssetMust(add_resp_lua), []string{
		rootKey,
		reqKey,
		respKey,
	}, reqSeq, data, 3600*24)
	if err != nil {
		return err
	}
	return
}
